#include "PlayerEntityStates.hpp"
#include "PlayerEntity.hpp"
#include "HostileEntity.hpp"
#include "AnimatedSprite.hpp"
#include "../MFSMachine.hpp"
#include "../Particles/EmitterManager.hpp"
#include "../MMessage.hpp"
#include "../MessageDispatcher.hpp"
#include "../SceneManager.hpp"
#include "../InputManager.hpp"
#include "../KeysDefinitions.hpp"
#include "../ResourceManagers/Mesh3D.hpp"
#include "PlasmaCannonStateNames.hpp"
#include "PlasmaCannonStates.hpp"
#include "PlasmaCannon.hpp"

#include <iostream>

using namespace std;

//! PLAYER_LISTEN
void PlayerListen::handleMessage(PlayerEntity *pEntity, MMessage *pMsg)
{
	switch(pMsg->getCommand())
	{
	case MSG_CMD_HANDLE_COLL:
		if(pEntity->getStateMachine()->getCurrentState()->getStateName() != PLESN_EXPLODE &&
			pEntity->getStateMachine()->getCurrentState()->getStateName() != PLESN_DIE)
			pEntity->getStateMachine()->changeState(new PlayerExplode());
		break;

	case MSG_CMD_DIE:
		pEntity->getStateMachine()->changeState(new PlayerDie());
		break;

	case MSG_CMD_KEYPRESS:
		int key = *(static_cast<int*>(pMsg->getAddInfo()));

		switch(key)
		{
		case KEY_LEFT:
			if(pEntity->getStateMachine()->getCurrentState()->getStateName() != PLESN_MOVE_LEFT)
				pEntity->getStateMachine()->changeState(new PlayerMoveLeft());
			break;

		case KEY_RIGHT:
			if(pEntity->getStateMachine()->getCurrentState()->getStateName() != PLESN_MOVE_RIGHT)
				pEntity->getStateMachine()->changeState(new PlayerMoveRight());
			break;

		case KEY_SPACE:
			if(pEntity->getCannon()->getStateMachine()->getCurrentState()->getStateName() != PCSN_SHOT)
				pEntity->getCannon()->getStateMachine()->changeState(new PlasmaCannonShot());
			//if(pEntity->getStateMachine()->getCurrentState()->getStateName() != PLESN_ATTACK)
			//	pEntity->getStateMachine()->changeState(new PlayerAttack());
			break;
		}
		break;
	}
}

void PlayerListen::beginState(PlayerEntity *)
{
}

void PlayerListen::updateState(PlayerEntity *, clock_t)
{
}

void PlayerListen::endState(PlayerEntity *)
{
}

//! PLAYER_IDLE
void PlayerIdle::beginState(PlayerEntity *)
{
}

void PlayerIdle::updateState(PlayerEntity *, clock_t)
{
}

void PlayerIdle::endState(PlayerEntity *)
{
}

//! PLAYER_MOVE
void PlayerMove::beginState(PlayerEntity *)
{
}

void PlayerMove::updateState(PlayerEntity *, clock_t)
{
}

void PlayerMove::endState(PlayerEntity *)
{
}

//! PLAYER_MOVE_LEFT
void PlayerMoveLeft::beginState(PlayerEntity *)
{
	m_fAccelFx = 0.15f;
	m_fCurrAccel = 0.0f;
	m_fCurrRotAngle = 0.0f;
	m_fMaxRot = 30.0f;
}

void PlayerMoveLeft::updateState(PlayerEntity *pEntity, clock_t tick)
{
	if(m_fCurrAccel > m_fAccelFx)
		m_fCurrAccel = m_fAccelFx;

	if(m_fCurrRotAngle > m_fMaxRot)
		m_fCurrRotAngle = m_fMaxRot;

	MVector3D translation;
	translation.x = -m_fCurrAccel;
	pEntity->translate(translation);

	if(InputManager::getInstance()->lookUpKeyStatus(KEY_LEFT) == KEY_RELEASED)
		pEntity->getStateMachine()->changeState(new PlayerIdle());

	if(m_fCurrAccel < m_fAccelFx)
		m_fCurrAccel += m_fAccelFx*tick / 2500.0f;

	if(m_fCurrRotAngle < m_fMaxRot)
	{
		m_fCurrRotAngle += 15.0 * tick / 1000.0f;
		const_cast<Mesh3D*>(pEntity->getMesh())->rotateZ(22.5*tick/1000.0f);
	}
}

void PlayerMoveLeft::endState(PlayerEntity* pEntity)
{
	float fAngle = const_cast<Mesh3D*>(pEntity->getMesh())->getRotationZ();
	const_cast<Mesh3D*>(pEntity->getMesh())->rotateZ(-fAngle);
}

//! PLAYER_MOVE_RIGHT
void PlayerMoveRight::beginState(PlayerEntity *)
{
	m_fAccelFx = 0.15f;
	m_fCurrAccel = 0.0f;
	m_fCurrRotAngle = 0.0f;
	m_fMaxRot = 30.0f;
}

void PlayerMoveRight::updateState(PlayerEntity *pEntity, clock_t tick)
{
	if(m_fCurrAccel > m_fAccelFx)
		m_fCurrAccel = m_fAccelFx;

	if(m_fCurrRotAngle > m_fMaxRot)
		m_fCurrRotAngle = m_fMaxRot;

	MVector3D translation;
	translation.x = m_fCurrAccel;
	pEntity->translate(translation);

	if(InputManager::getInstance()->lookUpKeyStatus(KEY_RIGHT) == KEY_RELEASED)
		pEntity->getStateMachine()->changeState(new PlayerIdle());

	if(m_fCurrAccel < m_fAccelFx)
		m_fCurrAccel += m_fAccelFx*tick / 3000.0f;

	if(m_fCurrRotAngle < m_fMaxRot)
	{
		m_fCurrRotAngle += 15.0 * tick / 1000.0f;
		const_cast<Mesh3D*>(pEntity->getMesh())->rotateZ(-(22.5*tick/1000.0f));
		cout << "rot: " << m_fCurrRotAngle << endl;
	}
	else
		cout << "over 45" << endl;
}

void PlayerMoveRight::endState(PlayerEntity* pEntity)
{
	float fAngle = const_cast<Mesh3D*>(pEntity->getMesh())->getRotationZ();
	const_cast<Mesh3D*>(pEntity->getMesh())->rotateZ(-fAngle);
}

//! PLAYER_ATTACK
void PlayerAttack::beginState(PlayerEntity * pEntity)
{
	float fScale = 0.5;
	MVector3D pos = pEntity->getPosition();
	pos.z += const_cast<Mesh3D*>(pEntity->getMesh())->getMinimum(Z_AXIS) - 0.5*fScale;
	m_pGunfire = new AnimatedSprite("gunfire.png"/*"expl2.png"*/, 2, 100, pos, true, fScale, fScale);
	SceneManager::GetInstance()->RegisterEntity(m_pGunfire);

	pos.z -= 1.0f;
	m_pBullets = new AnimatedSprite("shots.png", 4, 50, pos, true, 0.25);
	SceneManager::GetInstance()->RegisterEntity(m_pBullets);

	m_iCooldown = 15;

	m_pVec = new vector<int>();
	SceneManager::GetInstance()->getDynamicIDS(m_pVec);
}

void PlayerAttack::updateState(PlayerEntity *pEntity, clock_t tick)
{
	if(InputManager::getInstance()->lookUpKeyStatus(KEY_RIGHT) == KEY_PRESSED)
	{
		m_pGunfire->translate(MVector3D(0.15, 0.0, 0.0));
		m_pBullets->translate(MVector3D(0.15, 0.0, 0.0));
		pEntity->translate(MVector3D(0.15, 0.0, 0.0));
	}
	else if(InputManager::getInstance()->lookUpKeyStatus(KEY_LEFT) == KEY_PRESSED)
	{
		m_pGunfire->translate(MVector3D(-0.15, 0.0, 0.0));
		m_pBullets->translate(MVector3D(-0.15, 0.0, 0.0));
		pEntity->translate(MVector3D(-0.15, 0.0, 0.0));
	}

	if(InputManager::getInstance()->lookUpKeyStatus(KEY_SPACE) == KEY_RELEASED)
	{
		//if(InputManager::getInstance()->lookUpKeyStatus(KEY_RIGHT) == KEY_PRESSED)
			//pEntity->getStateMachine()->changeState(
		pEntity->getStateMachine()->changeState(new PlayerIdle());
	}

	if(m_iCooldown == 15)
	{
		vector<int>::iterator currElement = (*m_pVec).begin();
		vector<int>::iterator endElement  = (*m_pVec).end();

		for(currElement; currElement != endElement; ++currElement)
		{
			Entity3D* pHostile = static_cast<Entity3D*>(SceneManager::GetInstance()->GetEntityByID((*currElement)));
			pEntity->shotAutocannon(pHostile);
		}
	}

	m_iCooldown -= tick/1000.0f;
	if(m_iCooldown <= 0)
		m_iCooldown = 15;


	m_pGunfire->translate(MVector3D(0.0, 0.0, -0.015));
	m_pBullets->translate(MVector3D(0.0, 0.0, -0.015));
}

void PlayerAttack::endState(PlayerEntity *)
{
	delete m_pVec;

	SceneManager::GetInstance()->UnregisterEntity(m_pGunfire->getEntityID());
	SceneManager::GetInstance()->UnregisterEntity(m_pBullets->getEntityID());
}

//! PLAYER_EXPLODE
PlayerExplode::~PlayerExplode()
{
}

void PlayerExplode::beginState(PlayerEntity *pEntity)
{
	m_pExplodeAnim = new AnimatedSprite("expl2.png", 11, 75, const_cast<MVector3D&>(pEntity->getPosition()), false, 2.0f);
	SceneManager::GetInstance()->RegisterEntity(m_pExplodeAnim);
}

void PlayerExplode::updateState(PlayerEntity* pEntity, clock_t)
{
	if(m_pExplodeAnim->isOver())
		pEntity->getStateMachine()->changeState(new PlayerDie());
}

void PlayerExplode::endState(PlayerEntity* pEntity)
{
	SceneManager::GetInstance()->UnregisterEntity(m_pExplodeAnim->getEntityID());
	//MMessage* pMsg = new MMessage(MSG_CMD_DIE, 0, NULL);
	//MessageDispatcher::getInstance()->dispatchMessage(pMsg, pEntity->getEntityID(), pEntity->getEntityID());
}

//! PLAYER_DIE

PlayerDie::~PlayerDie()
{
}

void PlayerDie::beginState(PlayerEntity* pEntity)
{
	m_pExplosionEmitter = new BaseEmitter("fx_med.png", 250, 250);
}

void PlayerDie::updateState(PlayerEntity *pEntity, clock_t)
{
	static bool added = false;
	if(!added)
	{
		added = true;
		EmitterManager::GetInstance()->AddEmitter(m_pExplosionEmitter);
	}

	if(m_pExplosionEmitter->isDepleted())
	{
		EmitterManager::GetInstance()->removeEmitter(m_pExplosionEmitter);
		SceneManager::GetInstance()->UnregisterEntity(pEntity->getEntityID());
		//pEntity->getStateMachine()->changeState(new PlayerIdle);
	}
}

void PlayerDie::endState(PlayerEntity *pEntity)
{
	//pEntity->setVisibility(false);
	//SceneManager::GetInstance()->UnregisterEntity(pEntity->getEntityID());
}

//EOF
